﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Xml;

namespace Fulcrum.ControlGenerator
{
    /// <summary>
    /// Holds configuration data for a given control.
    /// </summary>
    class ControlXmlConfiguration : Fulcrum.ControlGenerator.IControlConfiguration
    {
        List<ITemplatePartConfiguration> templateParts = new List<ITemplatePartConfiguration>();
        List<IDependencyPropertyConfiguration> dependencyProperties = new List<IDependencyPropertyConfiguration>();
        List<IAttachedDependencyPropertyConfiguration> attachedDependencyProperties = new List<IAttachedDependencyPropertyConfiguration>();
        List<IRoutedCommandBindingConfiguration> routedCommands = new List<IRoutedCommandBindingConfiguration>();
        List<IRoutedCommandBindingConfiguration> routedCommandBindings = new List<IRoutedCommandBindingConfiguration>();
        List<IRoutedEventConfiguration> routedEvents = new List<IRoutedEventConfiguration>();

        SortedDictionary<string, string> usingNamespaces = new SortedDictionary<string, string>(StringComparer.Ordinal);

        public ControlXmlConfiguration(XmlReader xmlReader)
        {
            ReadAttributes(xmlReader);

            ReadChildElements(xmlReader);
        }

        private void ReadChildElements(XmlReader xmlReader)
        {
            xmlReader.Read();

            while (xmlReader.IsStartElement())
            {
                ProcessChildElement(xmlReader);
            }

            xmlReader.ReadEndElement();
        }

        void AddNamespace(string namespaceName)
        {
            this.usingNamespaces[namespaceName] = namespaceName;
        }

        public string Name
        {
            get;
            private set;
        }

        public string Location
        {
            get;
            private set;
        }

        public string Namespace
        {
            get;
            private set;
        }

        public string Summary
        {
            get;
            private set;
        }

        public string Remarks
        {
            get;
            private set;
        }

        public ICollection<string> UsingNamespaces
        {
            get
            {
                return this.usingNamespaces.Keys;
            }
        }

        void ReadAttributes(XmlReader xmlReader)
        {
            this.Name = xmlReader.GetAttribute("name");
            this.Namespace = xmlReader.GetAttribute("namespace");
            this.Summary = xmlReader.GetAttribute("summary");
            this.Remarks = xmlReader.GetAttribute("remarks");
            this.Location = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "location", String.Empty);

            this.HasAutomationPeer = XmlReaderHelp.GetOptionalBoolAttributeValue(xmlReader, "hasAutomationPeer", false);
            this.AutomationPeerName = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "automationPeerName", String.Format("{0}AutomationPeer", this.Name));
            this.AutomationPeerArguments = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "automationPeerArguments", String.Empty);

            this.OverrideStyleMetadata = XmlReaderHelp.GetOptionalBoolAttributeValue(xmlReader, "overrideStyleMetadata", true);

            string propertyChangedType = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "propertyChangeEvent", "DotNetEvent");

            switch (propertyChangedType)
            {
                case "RoutedEvent":
                    this.PropertyChangedEventType = PropertyChangedEventType.RoutedEvent;
                    break;
                case "DotNetEvent":
                    this.PropertyChangedEventType = PropertyChangedEventType.DotNetEvent;
                    break;
                default:
                    throw new ApplicationException("Invalid property changed type");
            }

            ProcessLocalizationSettings(xmlReader);
        }

        private void ProcessLocalizationSettings(XmlReader xmlReader)
        {
            var localizationCategory = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "localizationCategory", "None");
            var localizationModifiability = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "localizationModifiability", "Unmodifiable");
            var localizationReadability = XmlReaderHelp.GetOptionalAttributeValue(xmlReader, "localizationReadability", "Unreadable");

            this.LocalizationCategory = (LocalizationCategory)Enum.Parse(typeof(LocalizationCategory), localizationCategory);
            this.LocalizationModifiability = (Modifiability)Enum.Parse(typeof(Modifiability), localizationModifiability);
            this.LocalizationReadability = (Readability)Enum.Parse(typeof(Readability), localizationReadability);
        }

        void ProcessChildElement(XmlReader xmlReader)
        {
            switch (xmlReader.Name)
            {
                case "TemplatePart":
                    var templatePart = CreateTemplatePartConfiguration(xmlReader);
                    this.templateParts.Add(templatePart);
                    break;
                case "Using":
                    var namespaceName = xmlReader.GetAttribute("name");
                    AddNamespace(namespaceName);
                    xmlReader.Read();
                    break;
                case "DependencyProperty":
                    var dependencyProperty = CreateDependencyPropertyConfiguration(xmlReader);
                    this.dependencyProperties.Add(dependencyProperty);
                    break;
                case "AttachedDependencyProperty":
                    var attachedDependencyProperty = CreateAttachedDependencyPropertyConfiguration(xmlReader);
                    this.attachedDependencyProperties.Add(attachedDependencyProperty);
                    break;
                case "RoutedCommand":
                    var routedCommand = CreateRoutedCommandConfiguration(xmlReader);
                    this.routedCommands.Add(routedCommand);
                    break;
                case "CommandBinding":
                    var commandBinding = CreateCommandBindingConfiguration(xmlReader);
                    this.routedCommandBindings.Add(commandBinding);
                    break;
                case "RoutedEvent":
                    var routedEvent = CreateRoutedEventConfiguration(xmlReader);
                    this.routedEvents.Add(routedEvent);
                    break;
                default:
                    Debug.Fail("Invalid element");
                    break;
            }
        }

        protected virtual IRoutedEventConfiguration CreateRoutedEventConfiguration(XmlReader xmlReader)
        {
            var routedEvent = new RoutedEventXmlConfiguration(xmlReader);
            return routedEvent;
        }

        protected virtual IRoutedCommandBindingConfiguration CreateCommandBindingConfiguration(XmlReader xmlReader)
        {
            var commandBinding = new RoutedCommandBindingXmlConfiguration(xmlReader);
            return commandBinding;
        }

        protected virtual IRoutedCommandBindingConfiguration CreateRoutedCommandConfiguration(XmlReader xmlReader)
        {
            var routedCommand = new RoutedCommandXmlConfiguration(this, xmlReader);
            return routedCommand;
        }

        protected virtual IAttachedDependencyPropertyConfiguration CreateAttachedDependencyPropertyConfiguration(XmlReader xmlReader)
        {
            var attachedDependencyProperty = new AttachedDependencyPropertyXmlConfiguration(xmlReader);
            return attachedDependencyProperty;
        }

        protected virtual IDependencyPropertyConfiguration CreateDependencyPropertyConfiguration(XmlReader xmlReader)
        {
            var dependencyProperty = new DependencyPropertyXmlConfiguration(xmlReader);
            return dependencyProperty;
        }

        protected virtual ITemplatePartConfiguration CreateTemplatePartConfiguration(XmlReader xmlReader)
        {
            var templatePart = new TemplatePartXmlConfiguration(xmlReader);
            return templatePart;
        }

        public PropertyChangedEventType PropertyChangedEventType
        {
            get;
            private set;
        }

        public bool HasAutomationPeer
        {
            get;
            private set;
        }

        public string AutomationPeerName
        {
            get;
            private set;
        }

        public string AutomationPeerArguments
        {
            get;
            private set;
        }

        public bool OverrideStyleMetadata
        {
            get;
            private set;
        }

        public LocalizationCategory LocalizationCategory
        {
            get;
            private set;
        }

        public Modifiability LocalizationModifiability
        {
            get;
            private set;
        }

        public Readability LocalizationReadability
        {
            get;
            private set;
        }

        public ICollection<ITemplatePartConfiguration> TemplateParts
        {
            get
            {
                return this.templateParts;
            }
        }

        public ICollection<IDependencyPropertyConfiguration> DependencyProperties
        {
            get
            {
                return this.dependencyProperties;
            }
        }

        public ICollection<IAttachedDependencyPropertyConfiguration> AttachedDependencyProperties
        {
            get
            {
                return this.attachedDependencyProperties;
            }
        }

        public ICollection<IRoutedCommandBindingConfiguration> RoutedCommands
        {
            get
            {
                return this.routedCommands;
            }
        }

        public ICollection<IRoutedCommandBindingConfiguration> RoutedCommandBindings
        {
            get
            {
                return this.routedCommandBindings;
            }
        }

        public ICollection<IRoutedEventConfiguration> RoutedEvents
        {
            get
            {
                return this.routedEvents;
            }
        }

    }
}
